package sg.edu.nus.iss.billing.service.bill;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import sg.edu.nus.iss.billing.common.Util;
import sg.edu.nus.iss.billing.common.dataHandling.DataFormat;
import sg.edu.nus.iss.billing.dao.account.AccountDAO;
import sg.edu.nus.iss.billing.dao.account.IAccountDAO;
import sg.edu.nus.iss.billing.dao.bill.BillDAO;
import sg.edu.nus.iss.billing.dao.subscription.SubscriptionDAO;
import sg.edu.nus.iss.billing.service.subscription.SubscriptionImpl;
import sg.edu.nus.iss.billing.vo.account.AccountVO;
import sg.edu.nus.iss.billing.vo.bill.BillDetailVO;
import sg.edu.nus.iss.billing.vo.subscription.CableTvVO;
import sg.edu.nus.iss.billing.vo.subscription.DigitalVoiceVO;
import sg.edu.nus.iss.billing.vo.subscription.MobileVoiceVO;
import sg.edu.nus.iss.billing.vo.subscription.SubscriptionVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.ChannelFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.FeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.LocalCallFeatureVO;

public class BillImpl implements IBill {
	 int width = 100;
     int lwidth = 120;
     int mwidth = 112;
     int decimalwidth =8;
     BufferedWriter bufferedWriter = null;
	 DecimalFormat df = new DecimalFormat("0.00");
     
	@Override
	public int generateBill(Date date) {
		// TODO Auto-generated method stub
		//Get all the account
		IAccountDAO accountDAO = new AccountDAO();
		List<AccountVO> listAccount = accountDAO.getAllAccounts();
		for(Iterator<AccountVO> i = listAccount.iterator(); i.hasNext(); ) {
			AccountVO account = i.next();
			String status = account.getStatus();
			
			System.out.println("AccountNo::"+ account.getAccountNo());
			if(status.equals(Util.ACCOUNT_STATUS_ACTIVE))
			{
				//Construct the BufferedWriter object
				try
				{
				String fileName = Util.getFileNamePattern(account.getAccountNo(), date);
	            bufferedWriter = new BufferedWriter(new FileWriter("data//"+fileName));
	            
	            //Start writing to the output stream
	            DataFormat bill= new DataFormat();  bufferedWriter.newLine();
	            bufferedWriter.write(bill.getFormattedLine("One Billing Ltd", lwidth, 2));
	            bufferedWriter.newLine();
	            bufferedWriter.write(bill.getFormattedLine("67 Ubi Avenue 01, Starhub Green Singapore 283292", lwidth, 2));
	            bufferedWriter.newLine(); 	
	          
	            bufferedWriter.newLine();
	            Date dateOfBill = new Date();
	            Calendar cal = Calendar.getInstance();
                cal.setTime(dateOfBill);
                cal.add(Calendar.WEEK_OF_MONTH,2);

	            bufferedWriter.write(bill.getFormattedLine("Date of Bill :"+Util.getFormattedDateWithoutTime(dateOfBill), lwidth, 3));
	            bufferedWriter.newLine();
	            bufferedWriter.write(bill.getFormattedLine("Due Date    :"+ Util.getFormattedDateWithoutTime(cal.getTime()), lwidth, 3));
	            bufferedWriter.newLine();
	            bufferedWriter.write(bill.getFormattedLine("Account No:"+ account.getAccountNo(), lwidth, 3));
	            bufferedWriter.newLine();
	            bufferedWriter.write(bill.getFormattedLine("Bill No:"+ Util.getFileNamePattern(account.getAccountNo(), dateOfBill).replace(".txt", ""), lwidth, 3));
	            bufferedWriter.newLine();
	            
	            bufferedWriter.write("YOUR ACCOUNT AT A GLANCE");
	            String lblPrevBalance ="Previous Balance";
	            String lblPayments =   "Payments";
	            String lblCurrentCharges= "Current Charges Due on "+Util.getFormattedDateWithoutTime(cal.getTime());
	            String lblPleasePay = "Total Outstanding Balance";
	            
	            bufferedWriter.newLine();
	            Double prevBalance = new PaymentImpl().getLastPaymentTotalAmt(account.getAccountNo(), Util.getSystemDate());
	            lblPrevBalance =bill.getFormattedLine(lblPrevBalance, width, 1);
		        bufferedWriter.write(lblPrevBalance+bill.getFormattedLine(df.format(prevBalance),decimalwidth, 3));
		        bufferedWriter.newLine();
		        
		        lblPayments =bill.getFormattedLine(lblPayments, width, 1);
		        bufferedWriter.write(lblPayments+bill.getFormattedLine("-"+df.format(prevBalance), decimalwidth, 3));
		        bufferedWriter.newLine();
		        
		        Double currentCharges = new SubscriptionImpl().getThisMonthTotalCharges(account);
		        lblCurrentCharges =bill.getFormattedLine(lblCurrentCharges, width, 1);
		        
		        bufferedWriter.write(lblCurrentCharges+bill.getFormattedLine(df.format(currentCharges), decimalwidth, 3));
		        bufferedWriter.newLine();
		        
		        Double pleasepay = currentCharges; //assume customer pay bill regularly
		        lblPleasePay =bill.getFormattedLine(lblPleasePay, width, 1);
		        bufferedWriter.write(lblPleasePay+bill.getFormattedLine(df.format(pleasepay), decimalwidth, 3));
		        bufferedWriter.newLine();
		        
	            bufferedWriter.newLine();
	            bufferedWriter.newLine();

		        bufferedWriter.write(bill.getFormattedLine("_________________________________________________________", lwidth, 2));
		        bufferedWriter.newLine();
	            bufferedWriter.write("Summary - Current Charges");
	            bufferedWriter.newLine();
	            String blank =bill.getFormattedLine("", width, 3);
	            bufferedWriter.write(blank+ bill.getFormattedLine("Amount($)", decimalwidth, 2));
	            bufferedWriter.write(bill.getFormattedLine("Total($)", 12, 2));
	            bufferedWriter.newLine();
				
				SubscriptionDAO subscriptionDAO = new SubscriptionDAO();
				double totalBeforeGST= 0;
				//double GST = 0;
				//double total =0;
				List<SubscriptionVO> subscribedPlanList=  subscriptionDAO.getSubscriptionForAcct(account.getAccountNo());
				
				System.out.println("AccountNo::"+ account.getAccountNo()+"has "+ subscribedPlanList.size());
				
					for(Iterator<SubscriptionVO> subscribed = subscribedPlanList.iterator(); subscribed.hasNext(); ) {
						//Subscription Main Plan
						 SubscriptionVO subscribedPlan = subscribed.next();
						if(subscribedPlan.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
						{
						 bufferedWriter.write(subscribedPlan.getName());
				         bufferedWriter.newLine();
						 
				         double subscriptionCharges = 0;
				         String lblUsageCharges ="-Usage Charges";
				         double featureTotalCharges = 0;
				         
				         System.out.println("subscribedPlan::"+ subscribedPlan);
				         
				         //CableTV
				         if(subscribedPlan instanceof CableTvVO)
				         {
				        	 CableTvVO cableTVVO = (CableTvVO)subscribedPlan;
				        	 lblUsageCharges = "-Add Channel Charges";
				        	 if(cableTVVO.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
				        	 {
				        		 subscriptionCharges =cableTVVO.getMonthlySuscription();
				        		 
				        		 List<ChannelFeatureVO> addonfeatureList= cableTVVO.getAllAddonChannel();
				        		 for(Iterator<ChannelFeatureVO> addonfeature = addonfeatureList.iterator();addonfeature.hasNext();)
				        		 {
				        			 FeatureVO feature = addonfeature.next();
				        			 featureTotalCharges += getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate());
				        			 System.out.println("Feature::"+ feature.getName()+"charges "+getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate()));
				        		 }
				        	 }
				         }
				         //DigitalVoice
				         else if(subscribedPlan instanceof DigitalVoiceVO)
				         {
				        	 DigitalVoiceVO digitalVoiceVO = (DigitalVoiceVO)subscribedPlan;
				        	 if(digitalVoiceVO.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
				        	 {
				        		 subscriptionCharges =digitalVoiceVO.getMonthlySuscription();
				        		 
				        		 //Local Call is Mandatory
				        		 FeatureVO localCall = new LocalCallFeatureVO();
				        		 localCall = digitalVoiceVO.getLocalCallFeatureVO();
				        		 featureTotalCharges += getFeatureRate(localCall, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 
				        		 List<FeatureVO> addonfeatureList= digitalVoiceVO.getAllOptionalFeature();
				        		 for(Iterator<FeatureVO> addonfeature = addonfeatureList.iterator();addonfeature.hasNext();)
				        		 {
				        			 FeatureVO feature = addonfeature.next();
				        			 featureTotalCharges += getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 }
				        	 }
				         }
				         //MobileVoice
				         else if(subscribedPlan instanceof MobileVoiceVO)
				         {
				        	 MobileVoiceVO mobileVoiceVO = (MobileVoiceVO)subscribedPlan;
				        	 if(mobileVoiceVO.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
				        	 {
				        		 subscriptionCharges =mobileVoiceVO.getMonthlySuscription();
				        		 
				        		 //Local Call is Mandatory
				        		 FeatureVO localCall = new LocalCallFeatureVO();
				        		 localCall = mobileVoiceVO.getLocalCallFeatureVO();
				        		 featureTotalCharges += getFeatureRate(localCall, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 
				        		 List<FeatureVO> addonfeatureList= mobileVoiceVO.getAllOptionalFeature();
				        		 for(Iterator<FeatureVO> addonfeature = addonfeatureList.iterator();addonfeature.hasNext();)
				        		 {
				        			 FeatureVO feature = addonfeature.next();
				        			 featureTotalCharges += getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 }
				        	 }
				         }
				         
				         System.out.println("featureTotalCharges::"+ featureTotalCharges);
				         System.out.println("Subscription Charges::"+ subscriptionCharges);
				         
				         String lblSubscriptionCharges ="-Subscription Charges";
				         lblSubscriptionCharges =bill.getFormattedLine(lblSubscriptionCharges, width, 1);
				         bufferedWriter.write(lblSubscriptionCharges+bill.getFormattedLine(df.format(subscriptionCharges),decimalwidth, 3));
				         bufferedWriter.newLine();
				         lblUsageCharges=  bill.getFormattedLine(lblUsageCharges, width, 1);
				         bufferedWriter.write(lblUsageCharges+bill.getFormattedLine(df.format(featureTotalCharges),decimalwidth, 3));
			             bufferedWriter.newLine();
			             
			             //Print the Total Subscription Charges + Add-On Charges for Plan
				         String lblbeforeGST ="";
				         lblbeforeGST =bill.getFormattedLine(lblbeforeGST, mwidth, 1);
				 		
			             totalBeforeGST += subscriptionCharges + featureTotalCharges;
			             bufferedWriter.write(lblbeforeGST+bill.getFormattedLine(df.format(subscriptionCharges + featureTotalCharges), decimalwidth, 3));
			            
			             bufferedWriter.newLine();
			             bufferedWriter.newLine();
						}
					}
					
					 
					 printTotalCharges(bill, totalBeforeGST);
					 
			         bufferedWriter.newLine();
			         bufferedWriter.newLine();
			         bufferedWriter.write(bill.getFormattedLine("_________________________________________________________", lwidth, 2));
			         bufferedWriter.newLine();
			         bufferedWriter.write(bill.getFormattedLine("Account Details", lwidth, 2));
			         
			         totalBeforeGST =0;
			         for(Iterator<SubscriptionVO> subscribed = subscribedPlanList.iterator(); subscribed.hasNext(); ) {
						//Subscription Main Plan
						 SubscriptionVO subscribedPlan = subscribed.next();
						 
						 if(subscribedPlan.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
						 {
				         double subscriptionCharges = 0;
				         String lblFeatureName ="Feature";
				         double featureTotalCharges = 0;
				         //CableTV
				         if(subscribedPlan instanceof CableTvVO)
				         {
				        	 CableTvVO cableTVVO = (CableTvVO)subscribedPlan;
				        	 
				        	 if(cableTVVO.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
				        	 {	 //Print the Feature Details 
				        		 bufferedWriter.newLine();
					        	 bufferedWriter.write(cableTVVO.getName()); //Header
						         bufferedWriter.newLine();
						         bufferedWriter.newLine();
						         
				        		 subscriptionCharges =cableTVVO.getMonthlySuscription();
				        		 
				        		 List<ChannelFeatureVO> addonfeatureList= cableTVVO.getAllAddonChannel();
				        		 for(Iterator<ChannelFeatureVO> addonfeature = addonfeatureList.iterator();addonfeature.hasNext();)
				        		 {	
				        			 FeatureVO feature = addonfeature.next();
							         lblFeatureName = "-"+ feature.getName();
							         //TO Do seperate subscription charge and usage charge
							      
							         printFeatureDetails(bill, lblFeatureName, feature,subscribedPlan.getSubsId());
				        			 featureTotalCharges += getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 }
				        	 }
				        	 bufferedWriter.newLine();
				         }
				         //DigitalVoice
				         else if(subscribedPlan instanceof DigitalVoiceVO)
				         {
				        	 DigitalVoiceVO digitalVoiceVO = (DigitalVoiceVO)subscribedPlan;
				        	 
				        	 
				        	 if(digitalVoiceVO.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
				        	 {	
				        		 //Print the Detail of Digital Voice 
				        		 bufferedWriter.newLine();
					        	 bufferedWriter.write(digitalVoiceVO.getName()+" "+ digitalVoiceVO.getPhoneNumber());
						         bufferedWriter.newLine();
						         
				        		 subscriptionCharges =digitalVoiceVO.getMonthlySuscription();
				        		 List<FeatureVO> addonfeatureList= digitalVoiceVO.getAllOptionalFeature();
				        		 
				        		 //Local Call is Mandatory
				        		 FeatureVO localCall = new LocalCallFeatureVO();
				        		 localCall = digitalVoiceVO.getLocalCallFeatureVO();
				        		 lblFeatureName = localCall.getName();
				        		 printFeatureDetails(bill, lblFeatureName, localCall,subscribedPlan.getSubsId());
				        		 
			        			 featureTotalCharges += getFeatureRate(localCall, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 
				        		 for(Iterator<FeatureVO> addonfeature = addonfeatureList.iterator();addonfeature.hasNext();)
				        		 {
				        			 FeatureVO feature = addonfeature.next();
				        			 lblFeatureName = "-"+feature.getName();
							         //TO Do seperate subscription charge and usage charge
							      
							          printFeatureDetails(bill, lblFeatureName, feature,subscribedPlan.getSubsId());
				        			 featureTotalCharges += getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 }
				        	 }
				        	 bufferedWriter.newLine();
				         }
				         //MobileVoice
				         else if(subscribedPlan instanceof MobileVoiceVO)
				         {
				        	 MobileVoiceVO mobileVoiceVO = (MobileVoiceVO)subscribedPlan;
				        	 if(mobileVoiceVO.getStatus().equals(Util.ACCOUNT_STATUS_ACTIVE))
				        	 {	//Print the Detail of Digital Voice 
				        		 bufferedWriter.newLine();
					        	 bufferedWriter.write(mobileVoiceVO.getName()+" "+ mobileVoiceVO.getPhoneNumber());
						         bufferedWriter.newLine();
						         
				        		 subscriptionCharges =mobileVoiceVO.getMonthlySuscription();
				        		 
				        		 //Local Call is Mandatory
				        		 FeatureVO localCall = new LocalCallFeatureVO();
				        		 localCall = mobileVoiceVO.getLocalCallFeatureVO();
				        		 lblFeatureName = "-"+localCall.getName();
				        		 printFeatureDetails(bill, lblFeatureName, localCall,subscribedPlan.getSubsId());
				        		 
			        			 featureTotalCharges += getFeatureRate(localCall, subscribedPlan.getSubsId(), Util.getSystemDate());
			        			 
				        		 List<FeatureVO> addonfeatureList= mobileVoiceVO.getAllOptionalFeature();
				        		 for(Iterator<FeatureVO> addonfeature = addonfeatureList.iterator();addonfeature.hasNext();)
				        		 {
				        			 FeatureVO feature = addonfeature.next();
				        			 lblFeatureName = feature.getName();
							         //TO Do seperate subscription charge and usage charge
							      
							          printFeatureDetails(bill, lblFeatureName, feature,subscribedPlan.getSubsId());
				        			 featureTotalCharges += getFeatureRate(feature, subscribedPlan.getSubsId(), Util.getSystemDate());
				        		 }
				        	 }
				        	 bufferedWriter.newLine();
				         }
				         String lblSubscriptionCharges ="-Subscription Charges";
				         lblSubscriptionCharges =bill.getFormattedLine(lblSubscriptionCharges, width, 1);
				         bufferedWriter.write(lblSubscriptionCharges+bill.getFormattedLine(df.format(subscriptionCharges),decimalwidth, 3));
				         bufferedWriter.newLine();
				         
			             //Print the Total Subscription Charges + Add-On Charges for Plan
				         String lblbeforeGST ="";
				         lblbeforeGST =bill.getFormattedLine(lblbeforeGST, mwidth, 1);
				 		
			             totalBeforeGST += subscriptionCharges + featureTotalCharges;
			             
			             bufferedWriter.write(lblbeforeGST+ bill.getFormattedLine(df.format(subscriptionCharges + featureTotalCharges), decimalwidth, 3));
			             bufferedWriter.newLine();
			             bufferedWriter.newLine();
						 }
			         }
			         printTotalCharges(bill, totalBeforeGST);
			         
				}catch (FileNotFoundException ex) {
		            ex.printStackTrace();
		        } catch (IOException ex) {
		            ex.printStackTrace();
		        } finally {
		            //Close the BufferedWriter
		            try {
		                if (bufferedWriter != null) {
		                    bufferedWriter.flush();
		                    bufferedWriter.close();
		                }
		            } catch (IOException ex) {
		                ex.printStackTrace();
		            }
		        }
			}
			
		}

		//read the subscription
		//calculate the bill
		//output the bill to text file
		
		return 0;
	}

	private void printFeatureDetails(DataFormat bill, String lblFeatureName,
			FeatureVO feature, String subscriptionId) throws IOException {
		lblFeatureName =bill.getFormattedLine(lblFeatureName, width, 1);
		 bufferedWriter.write(lblFeatureName+bill.getFormattedLine(df.format(getFeatureRate(feature, subscriptionId, Util.getSystemDate())), decimalwidth, 3));
		 bufferedWriter.newLine();
	}
	private void printTotalCharges(DataFormat bill, double totalBeforeGST) throws IOException
	{	
		bufferedWriter.newLine();
		String lblTotalGST ="Total GST";
		lblTotalGST =bill.getFormattedLine(lblTotalGST, mwidth, 1);
		double GST = totalBeforeGST * 0.07;
        bufferedWriter.write(lblTotalGST+bill.getFormattedLine(df.format(GST), decimalwidth, 3));
        bufferedWriter.newLine();
        
        String lblTotalCurrentCharges ="Total Current Charges";
        lblTotalCurrentCharges =bill.getFormattedLine(lblTotalCurrentCharges, mwidth, 1);
		 double total = totalBeforeGST + GST;
		 
        bufferedWriter.write(lblTotalCurrentCharges+bill.getFormattedLine(df.format(total), decimalwidth, 3));
        bufferedWriter.newLine();
	}

	@Override
	public BillDetailVO getBill(String accountNo, Date billDate) {
		BillDAO billDAO= new BillDAO();
		return billDAO.getBill(accountNo, billDate);
	}
	
	private double getFeatureRate(FeatureVO feature,String subscriptionId,Date date)
	{
		return new SubscriptionImpl().getFeatureRate(feature, subscriptionId, date);
	}
}
